package xyz.scootaloo.oj.multithreading;

import xyz.scootaloo.console.app.common.Colorful;

import java.util.function.IntConsumer;

/**
 * 多线程
 * 同步锁
 * @author flutterdash@qq.com
 * @since 2021/3/25 22:17
 */
public class P1116 {

    static Colorful colorful = Colorful.INSTANCE;

    static class ZeroEvenOdd {
        private final int n;
        private volatile int currentNumber;
        private volatile boolean zero;
        private final boolean isEven;

        public ZeroEvenOdd(int n) {
            this.n = n;
            this.currentNumber = 1;
            this.zero = true;
            this.isEven = n % 2 == 1;
        }

        // printNumber.accept(x) outputs "x", where x is an integer.
        public synchronized void zero(IntConsumer printNumber) throws InterruptedException {
             do {
                 if (n == 0)
                     return;
                while (!zero) {
//                    System.out.println(colorful.red("zero-wait"));
                    wait();
                }

//                System.out.println(colorful.green("zero-notify"));
                printNumber.accept(0);

//                if (currentNumber == 0)
//                    currentNumber = 1;

                zero = false;
                notifyAll();
            } while (currentNumber < n);
        }

        public synchronized void even(IntConsumer printNumber) throws InterruptedException {
            do {
                if (n == 0)
                    return;
                // 假如当前数是单数，则等待
                while (zero || currentNumber % 2 == 1) {
                    if (currentNumber == n && isEven) {
                        notifyAll();
                        return;
                    }
//                    System.out.println(colorful.red("odd-wait"));
                    wait();
                }

//                System.out.println(colorful.green("odd-notify"));
                printNumber.accept(currentNumber);
                currentNumber++;
                zero = true;
                notifyAll();
            } while (currentNumber < n);
        }

        public synchronized void odd(IntConsumer printNumber) throws InterruptedException {
            do {
                if (n == 0)
                    return;
                while (zero || currentNumber % 2 == 0) {
                    if (currentNumber == n && !isEven) {
                        notifyAll();
                        return;
                    }
//                    System.out.println(colorful.red("even-wait"));
                    wait();
                }

//                 System.out.println(colorful.green("even-notify"));
                printNumber.accept(currentNumber);
                currentNumber++;
                zero = true;
                notifyAll();
            } while (currentNumber < n);
        }

    }

    public static void main(String[] args) {
        ZeroEvenOdd zeroEvenOdd = new ZeroEvenOdd(1);
        IntConsumer intConsumer = (integer) ->
                System.out.println(colorful.grey(Thread.currentThread().getName() + ": " + integer));
        Thread zero = new Thread(() -> {
            try {
                zeroEvenOdd.zero(intConsumer);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "zero");
        Thread even = new Thread(() -> {
            try {
                zeroEvenOdd.even(intConsumer);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "even");
        Thread odd = new Thread(() -> {
            try {
                zeroEvenOdd.odd(intConsumer);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "odd");

        even.start();
        odd.start();
        zero.start();
    }

}
